package com.tiger.admin.http.login;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiger.admin.Db;
import com.tiger.admin.http.common.member.MemberService;
import com.tiger.admin.http.encipher.EncipherService;
import com.tiger.cache.RedisService;
import com.tiger.db.entity.Member;
import com.tiger.db.entity.Teacher;
import com.tiger.db.entity.Users;
import com.tiger.utils.IpUtil;
import com.tiger.utils.ResponseUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apereo.cas.client.util.AbstractCasFilter;
import org.apereo.cas.client.validation.Assertion;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

import static java.util.concurrent.TimeUnit.SECONDS;

@RestController
@RequestMapping("/login")
public class LoginController {


    @Value("${casAuthServerLogout}")
    private String logoutUrl;

    private final LoginService loginService;
    private final MemberService memberService;

    private final Db db;

    private final RedisService redisService;

    private final EncipherService encipherService;


    @Value("${MaxLoginCount}")
    private byte maxLoginCount;


    public LoginController(LoginService loginService, MemberService memberService, Db db, RedisService redisService, EncipherService encipherService) {
        this.loginService = loginService;
        this.memberService = memberService;
        this.db = db;
        this.redisService = redisService;
        this.encipherService = encipherService;
    }

    @GetMapping("location")
    public void location(HttpServletRequest request) {
        loginService.ipToLogin(IpUtil.getIpAddr(request));
    }

    @GetMapping("status")
    public Object status(HttpServletRequest request) {
        HttpSession session = request.getSession();


        if(session.getAttribute("loginStatus") != null) {
            String account = (String) session.getAttribute("account");

            Member member = db.member.getOne(new QueryWrapper<Member>().eq("account", account));


            Instant now = Instant.now();
            long time = now.getEpochSecond();



            String[] uuids = UUID.randomUUID().toString().split("-");
            String salt = uuids[uuids.length - 1];

            String token = loginService.makeToken(member.getId(), time, salt);



            Map<String, Object> res = new HashMap<>();
            res.put("token", token);
            res.put("expire", loginService.getJwtExpire());
            res.put("belong", member.getBelong());
            res.put("refreshToken", "1");
            res.put("super", member.isCanSuper());
            res.put("name", member.getName());


            redisService.template.opsForValue().set(salt + ":" + member.getId(), "1");

            return  ResponseUtil.successRes(res);
        }

        return ResponseUtil.failRes();
    }

    @GetMapping("auth")
    public String auth(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String str = "您没有登陆权限，请联系管理员";
        HttpSession session = request.getSession();


        Assertion assertion = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
        if(assertion != null) {
            Principal principal  = assertion.getPrincipal();

            String loginName = principal.getName();

            Users users = db.users.getOne(new LambdaQueryWrapper<Users>().eq(Users::getAccount, loginName));
            System.out.println("users");
            System.out.println(users);
            if(users == null) {
                request.getSession().invalidate();
                return str;
            }

            Member member = db.member.getOne(new LambdaQueryWrapper<Member>().eq(Member::getAccount, loginName).eq(Member::getSource, users.getUserRole()));
            System.out.println("member");
            System.out.println(member);
            if(member == null) {
                request.getSession().invalidate();
                return str;
            }


            session.setAttribute("loginStatus", 1);
            session.setAttribute("account", users.getAccount());

            URL urlObj = new URL(request.getRequestURL().toString());
            String protocol = urlObj.getProtocol(); // 获取协议（如http, https）
            String host = urlObj.getHost(); // 获取主机名（域名）
            String redirectUrl = protocol + "://" + host;

            redirectUrl += "/admin/#/auth";

            response.sendRedirect(redirectUrl);
        }

        return str;

    }

    @PostMapping()
    public Map<String, Object> login(@RequestBody @Validated Dto data, HttpServletRequest request, HttpSession session) throws Exception {

        String password = encipherService.decrypt(session, data.getPassword());

        System.out.println(password);

        if(password == null) return ResponseUtil.failRes();


        ValueOperations<String, String> valueOps = redisService.template.opsForValue();
        Instant now = Instant.now();
        long time = now.getEpochSecond();
        long nextDayTime = now.plusSeconds(86400).getEpochSecond();

        // 将时间戳转换为日期
        LocalDate today = LocalDate.ofInstant(now, ZoneId.systemDefault());

        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMdd");



        String account = data.getAccount();


        String loginCountKey = "login.er." + account + today.format(formatter);
        int loginCount = 0;
        String tmp = valueOps.get(loginCountKey);


        if(tmp != null) {
            loginCount = Integer.parseInt(tmp);
            tmp = null;

            if(loginCount >= maxLoginCount) return ResponseUtil.failRes("今日登录失败超过最大次数了");
        }

        String lockKey = "login." + account;

        boolean lock = Boolean.TRUE.equals(valueOps.setIfAbsent(lockKey, "1", 10, SECONDS));
        if(!lock) return null;

        Member member = db.member.getOne(new QueryWrapper<Member>().select("name", "password", "id", "salt", "belong", "can_super", "enable").eq("account", account));


        if(member == null || !Objects.equals(memberService.buildPassword(password, member.getSalt()), member.getPassword())) {
            valueOps.getOperations().delete(lockKey);
            valueOps.set(loginCountKey, String.valueOf(loginCount + 1), nextDayTime - time, SECONDS);
            return ResponseUtil.failRes("账号或密码错误");
        }


        String[] uuids = UUID.randomUUID().toString().split("-");
        String salt = uuids[uuids.length - 1];

        String token = loginService.makeToken(member.getId(), time, salt);

        Map<String, Object> res = new HashMap<>();
        res.put("token", token);
        res.put("expire", loginService.getJwtExpire());
        res.put("belong", member.getBelong());
        res.put("refreshToken", "1");
        res.put("super", member.isCanSuper());
        res.put("name", member.getName());

        redisService.template.opsForValue().set(salt + ":" + member.getId(), "1");

        return  ResponseUtil.successRes(res);
    }

    @GetMapping("logout")
    public Object logout(HttpServletRequest request, HttpServletResponse response, @RequestAttribute("memberId") long memberId, @RequestAttribute("salt") String salt) throws IOException {
       request.getSession().invalidate();

       redisService.template.delete(salt + ":" + memberId);

       Member member = db.member.getOne(new LambdaQueryWrapper<Member>().eq(Member::getId, memberId));
       if(member.getSource() == 0) {
            return ResponseUtil.successRes();
       }else {
//           URL urlObj = new URL(request.getRequestURL().toString());
//           String protocol = urlObj.getProtocol(); // 获取协议（如http, https）
//           String host = urlObj.getHost(); // 获取主机名（域名）
//           String redirectUrl = protocol + "://" + host;


           String url = String.format(logoutUrl, "");


           return ResponseUtil.successRes(url);
       }




    }
}
